/*****************************************************************************//*!
* file  : can quene.c
* creat : apleilx
* data  : 2017/11/05
*******************************************************************************/
#include "os_obj.h"
#include "pincfg.h"
#include "sys_init.h"
#include "common.h"
#include "bsp_hal.h"
#include "can_quene.h"
#include "sys_ext.h"

extern CAN_HandleTypeDef hcan2;
simp_can_frame_ctr_type can2_quene;

static simp_can_frame_type can_rx_buff[16];
static simp_can_frame_type can_tx_buff[64];
static simp_can_frame_type can_tx_rt_buff[12];
static simp_can_cmd_type   stc_cmd[16];
static simp_can_cmd_type   sync_cmd[8];

#define can_quene		can2_quene
#define can_obj			hcan2
#define can_port		CAN2

/*******************************************************************************
* @brief  isr enable or disable
* \param[in] none
* \retval: none
*******************************************************************************/
__STATIC_INLINE void can_rx_intx_enable(void)
{
	can_port->IER |= CAN_IER_FMPIE0;
	can_port->IER |= CAN_IER_FMPIE1;
}

#define can_tx_intx_enable()  can_port->IER |= CAN_IER_TMEIE
#define can_tx_intx_disable() can_port->IER &= ~CAN_IER_TMEIE

/*******************************************************************************
* @brief  isr
* \param[in] none
* \retval: none
*******************************************************************************/
void CAN2_TX_IRQHandler(void)
{
	HAL_CAN_IRQHandler(&can_obj);

	while(can_port->TSR & CAN_TSR_TME)
	{
		if(SIMP_CAN_TX_IDLE == simp_can_transmit(&can_quene))
		{
			can_tx_intx_disable();
			break;
		}
	}
}

/*******************************************************************************
* @brief  isr
* \param[in] none
* \retval: none
*******************************************************************************/
void CAN2_RX0_IRQHandler(void)
{
	simp_can_frame_type rcv;
	uint32_t * pdat = (uint32_t *)can_obj.pRxMsg->Data;

	HAL_CAN_IRQHandler(&can_obj);

	rcv.dat[0].Val = pdat[0];
	rcv.dat[1].Val = pdat[1];
	rcv.len = can_obj.pRxMsg->DLC;
	rcv.remot = (can_obj.pRxMsg->RTR == CAN_RTR_DATA)?0:1;
	if(can_obj.pRxMsg->IDE == CAN_ID_STD)
	{
		rcv.id = can_obj.pRxMsg->StdId;
		rcv.id_mode = SIMP_CAN_ID_MODE_STD;
	}
	else
	{
		rcv.id = can_obj.pRxMsg->ExtId;
		rcv.id_mode = SIMP_CAN_ID_MODE_EXT; 
	}
	
	simp_can_receive(&can_quene, &rcv);

	can_rx_intx_enable();
}

/*******************************************************************************
* @brief  isr
* \param[in] none
* \retval: none
*******************************************************************************/
void CAN2_RX1_IRQHandler(void)
{
	simp_can_frame_type rcv;
	uint32_t * pdat = (uint32_t *)can_obj.pRx1Msg->Data;

	HAL_CAN_IRQHandler(&can_obj);

	rcv.dat[0].Val = pdat[0];
	rcv.dat[1].Val = pdat[1];
	rcv.len = can_obj.pRx1Msg->DLC;
	rcv.remot = (can_obj.pRx1Msg->RTR == CAN_RTR_DATA)?0:1;
	if(can_obj.pRx1Msg->IDE == CAN_ID_STD)
	{
		rcv.id = can_obj.pRx1Msg->StdId;
		rcv.id_mode = SIMP_CAN_ID_MODE_STD;
	}
	else
	{
		rcv.id = can_obj.pRx1Msg->ExtId;
		rcv.id_mode = SIMP_CAN_ID_MODE_EXT; 
	}

	simp_can_receive(&can_quene, &rcv);

	can_rx_intx_enable();
}

/*******************************************************************************
* @brief  isr
* \param[in] none
* \retval: none
*******************************************************************************/
void CAN2_SCE_IRQHandler(void)
{
	HAL_CAN_IRQHandler(&hcan2);
}

/*******************************************************************************
* @brief  can2 quene send to port
* \param[in] frame: can frame
* \retval: none
*******************************************************************************/
static void can_tx_send_reg(simp_can_frame_type * frame)
{
	uint8_t transmitmailbox;
	intx_alloc();
	
	if (0 == (can_port->TSR&CAN_TSR_TME))
	{
		return;
	}

	/* Select one empty transmit mailbox */
	if ((can_port->TSR&CAN_TSR_TME0) == CAN_TSR_TME0)
	{
		transmitmailbox = CAN_TXMAILBOX_0;
	}
	else if ((can_port->TSR&CAN_TSR_TME1) == CAN_TSR_TME1)
	{
		transmitmailbox = CAN_TXMAILBOX_1;
	}
	else
	{
		transmitmailbox = CAN_TXMAILBOX_2;
	}

	/* Set up the Id */
	//can_port->sTxMailBox[transmitmailbox].TIR &= CAN_TI0R_TXRQ;
	can_port->sTxMailBox[transmitmailbox].TIR = 0;
	if (SIMP_CAN_ID_MODE_STD == frame->id_mode)
	{
		if (frame->remot)
		{
			can_port->sTxMailBox[transmitmailbox].TIR |=
				((frame->id << 21U) | CAN_RTR_REMOTE);
		}
		else
		{
			can_port->sTxMailBox[transmitmailbox].TIR |=
				((frame->id << 21U) | CAN_RTR_DATA);
		}
	}
	else
	{
		if (frame->remot)
		{
			can_port->sTxMailBox[transmitmailbox].TIR |=
				(frame->id << 3U) | CAN_ID_EXT | CAN_RTR_REMOTE;
		}
		else
		{
			can_port->sTxMailBox[transmitmailbox].TIR |=
				(frame->id << 3U) | CAN_ID_EXT | CAN_RTR_DATA;
		}
	}

	/* Set up the DLC */
	frame->len &= (uint8_t)0x0000000F;
	can_port->sTxMailBox[transmitmailbox].TDTR &= (uint32_t)0xFFFFFFF0U;
	can_port->sTxMailBox[transmitmailbox].TDTR |= frame->len;

	/* Set up the data field */
	can_port->sTxMailBox[transmitmailbox].TDLR = frame->dat[0].uVal;
	can_port->sTxMailBox[transmitmailbox].TDHR = frame->dat[1].uVal;

	intx_disable();
	
	/* Request transmission */
	can_port->sTxMailBox[transmitmailbox].TIR |= CAN_TI0R_TXRQ;

	can_tx_intx_enable();
	
	intx_enable();
}

/*******************************************************************************
* @brief  can2 quene receive handle
* \param[in] none
* \retval: none
*******************************************************************************/
void can2_rx_handle(simp_can_frame_type * frame)
{
	can_dbg_print("CAN2 receive frame at < %d ms >: ", app_tick_get());
	can_dbg_print("id = 0x%08X, Len = %d: ", frame->id, frame->len);
	can_dbg_print("dat = 0x%08X, 0x%08X\n\n", frame->dat[0].uVal, frame->dat[1].uVal);
}

/*******************************************************************************
* @brief  can1 quene receive handle
* \param[in] none
* \retval: none
*******************************************************************************/
static void can_time_run(void)
{
	simp_can_time_run(&can_quene);
}

/*******************************************************************************
* @brief  is_tx_hal_empty
* \param[in] none
* \retval: none
*******************************************************************************/
static uint8_t is_tx_hal_empty(void)
{
	if((can_port->TSR & CAN_TSR_TME) == CAN_TSR_TME)
		return 1;
	return 0;
}

static uint8_t is_tx_hal_full(void)
{
	if((can_port->TSR & CAN_TSR_TME) == 0)
		return 1;
	return 0;
}

/*******************************************************************************
* @brief  can quene init
* \param[in] none
* \retval: none
*******************************************************************************/
static void quene_obj_init(void)
{
	intx_alloc();
	
	memset(&can_quene, 0, sizeof(can_quene));

	can_quene.rx_frame = can_rx_buff;
	can_quene.rx_buff_amount = sizeof(can_rx_buff) / sizeof(simp_can_frame_type);

	can_quene.tx_frame = can_tx_buff;
	can_quene.tx_buff_amount = sizeof(can_tx_buff) / sizeof(simp_can_frame_type);

	can_quene.tx_rt_frame = can_tx_rt_buff;
	can_quene.tx_rt_buff_amount = sizeof(can_tx_rt_buff) / sizeof(simp_can_frame_type);
	
	can_quene.tx_send = can_tx_send_reg;
	can_quene.rx_handle = can2_rx_handle;
	can_quene.is_tx_hal_empty = is_tx_hal_empty;
	can_quene.is_tx_hal_full = is_tx_hal_full;
	
	simp_can_cmd_init(
		&can_quene,
		stc_cmd,
		sizeof(stc_cmd)/sizeof(simp_can_cmd_type),
		sync_cmd,
		sizeof(sync_cmd)/sizeof(simp_can_cmd_type));
	
	intx_disable();

	vtask_list_add(&app_tick_task_list, can_time_run);

	intx_enable();
}

/*******************************************************************************
* @brief  can quene init
* \param[in] none
* \retval: none
*******************************************************************************/
void can2_quene_init(void)
{
	/* Request initialisation */
  	can_port->MCR |= CAN_MCR_INRQ ;
	can_port->MCR &= ~(uint32_t)CAN_MCR_DBF;
	can_port->MCR &= ~(uint32_t)CAN_MCR_INRQ;

	quene_obj_init();
	
	can_rx_intx_enable();
}